﻿using BSF.BaseService.NScript.Compiler;
using BSF.BaseService.NScript.Core;
using ICSharpCode.TextEditor.Document;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BSF.BaseService.NScript
{
    public partial class FrCodeEdit : Form
    {
        public FrCodeEdit()
        {
            InitializeComponent();

            this.rtbCode.Document.HighlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategy("C#");
            this.rtbCode.Encoding = System.Text.Encoding.Default;
           
        }

        FrDebug frdebug = new FrDebug();

        public class FileInfoItem
        {
            public string FileName;
            public string FullFileName;
            public bool isMainFile;
            public override string ToString()
            {
                return (isMainFile == true ? "[主]" : "") + FileName;
            }
        }



        private void TryToLoadMainFile()
        {
            try
            {
                foreach (var dir in GetSearchDirs())
                {

                    foreach (var filepath in System.IO.Directory.GetFiles(dir))
                    {
                        if (filepath.ToLower().EndsWith(".main.cs"))
                        {
                            OpenMainFile(filepath);
                            return;
                        }
                    }
                }
            }
            catch (Exception exp)
            {
            }
        }

        private List<string> GetSearchDirs()
        {

            List<string> dirs = new List<string>(); dirs.Add(AppDomain.CurrentDomain.BaseDirectory);
            string strsearchdirs = System.Configuration.ConfigurationManager.AppSettings["searchdirs"];
            strsearchdirs = (strsearchdirs == null ? "" : strsearchdirs);
            string[] searchdirs = strsearchdirs.Trim(';').Split(';');
            foreach (var dir in searchdirs)
            {
                if (!dirs.Contains(dir) && System.IO.Directory.Exists(dir))
                {
                    dirs.Add(dir);
                }
            }
            return dirs;
        }

        private void OpenMainFile(string mainFilePath)
        {
            CompilerInfoContext.CompilerInfoCache.ClearCache();
            CompilerInfo ci = new CompilerInfo().Parse(EnumSourceType.File, mainFilePath);
            var mainFileInfoItem = new FileInfoItem() { FileName = ci.MainFilePath.FileName, FullFileName = ci.MainFilePath.FullFileName, isMainFile = true };
            this.lbFileList.Items.Add(mainFileInfoItem);
            foreach (var file in ci.CodeFilePaths)
            {
                this.lbFileList.Items.Add(new FileInfoItem() { FileName = file.FileName, FullFileName = file.FullFileName, isMainFile = false });

            }
            OpenFileCode(mainFileInfoItem);
            this.lbFileList.SelectedItem = mainFileInfoItem;
        }


        int lastindex = -1; DateTime lastshowtime = DateTime.Now;
        private void showFileToolTip()
        {
            Point point = this.lbFileList.PointToClient(Control.MousePosition);
            int index = lbFileList.IndexFromPoint(point.X, point.Y);
            if (index >= 0 && index != lastindex && (DateTime.Now - lastshowtime) > TimeSpan.FromSeconds(5))
            {
                lastindex = index; lastshowtime = DateTime.Now;
                this.toolTip1.SetToolTip(lbFileList, (lbFileList.Items[index] as FileInfoItem).FullFileName);
            }
        }

        private FileInfoItem GetMainFileInfoItem()
        {
            foreach (var item in this.lbFileList.Items)
            {
                if (item is FileInfoItem)
                {
                    var fileinfoitem = (item as FileInfoItem);
                    if (fileinfoitem.isMainFile == true)
                    {
                        return fileinfoitem;
                    }
                }
            }
            throw new Exception("找不到主编译文件");
        }

        private void OpenFileCode(FileInfoItem fileinfoitem)
        {
            SaveFileCode();
            this.rtbCode.Tag = null;
            this.rtbCode.ResetText();// = "";

            this.rtbCode.Text = IOHelper.ReadAllText(fileinfoitem.FullFileName);
            this.rtbCode.Tag = fileinfoitem;
            this.rtbCode.Refresh();

        }

        public void SaveFileCode()
        {
            if (this.rtbCode.Tag != null)
            {
                var fileinfoitemtemp = (this.rtbCode.Tag as FileInfoItem);

                IOHelper.WriteAllText(fileinfoitemtemp.FullFileName, this.rtbCode.Text);
                PrintInfo(fileinfoitemtemp.FileName + " 已保存 " + DateTime.Now.ToString("yyyyMMdd HH:mm:ss"));
            }
        }

        public string GetMainCompilerTempFile()
        {
            string mainFileCode = IOHelper.ReadAllText(GetMainFileInfoItem().FullFileName) + "\n//编译时间:" + DateTime.Now.ToString("yyMMddHHmmssfff") + "\n";
            string compilertempMainFilePath = System.IO.Path.GetDirectoryName(GetMainFileInfoItem().FullFileName).TrimEnd('\\') + "\\" + GetMainFileInfoItem().FileName + "." + DateTime.Now.ToString("yyMMddHHmmssfff") + ".compiler";
            System.IO.File.WriteAllText(compilertempMainFilePath, mainFileCode);
            return compilertempMainFilePath;
        }

        public CompilerResult RunCompiler(EnumCompilerMode enumCompilerMode)
        {
            try
            {
                var mainFileInfoItem = GetMainFileInfoItem();
                if (mainFileInfoItem == null)
                {
                    throw new Exception("找不到主编译文件");
                }
                string mainFileCode = IOHelper.ReadAllText(mainFileInfoItem.FullFileName) + "\n//编译时间:" + DateTime.Now.ToString("yyMMddHHmmssfff") + "\n";
                string compilertempMainFilePath = System.IO.Path.GetDirectoryName(mainFileInfoItem.FullFileName).TrimEnd('\\') + "\\" + mainFileInfoItem.FileName + ".compiler";
                System.IO.File.WriteAllText(compilertempMainFilePath, mainFileCode);
                return NScriptHelper.RunCompiler(new CompilerParams() { EnumSourceType = EnumSourceType.File, CodeOrFileName = compilertempMainFilePath, EnumCompilerMode = enumCompilerMode });
            }
            catch (Exception exp)
            {
                throw exp;
            }
            finally
            {
                DeleteCompilerTempFiles();
            }
        }

        public void DeleteCompilerTempFiles()
        {
            try
            {
                var mainFileInfoItem = GetMainFileInfoItem();
                if (mainFileInfoItem != null)
                {
                    string[] files = System.IO.Directory.GetFiles(System.IO.Path.GetDirectoryName(mainFileInfoItem.FullFileName));
                    foreach (var file in files)
                    {
                        if (file.ToLower().EndsWith(".compiler") == true)
                        {
                            try
                            {
                                System.IO.File.Delete(file);
                            }
                            catch { }
                        }
                    }
                }
            }
            catch { }
        }

        private void ErrorCatch(Action action)
        {
            try
            {
                action.Invoke();
            }
            catch (Exception exp)
            {
                if (exp is NScript.Compiler.NScriptException)
                    MessageBox.Show((exp as NScriptException).MessageDetail);
                else
                    MessageBox.Show(exp.Message);
            }
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            ErrorCatch(() =>
            {
                OpenFileDialog fileDialog = new OpenFileDialog();
                fileDialog.Multiselect = false;
                fileDialog.Title = "请选择文件";
                fileDialog.Filter = "C#.Main主文件 (*.main.cs)|*.main.cs|所有文件 (*.*)|*.*";
                if (fileDialog.ShowDialog() == DialogResult.OK)
                {
                    this.lbFileList.Items.Clear();
                    string filepath = fileDialog.FileName;
                    OpenMainFile(filepath);
                }
            });
        }

        private void PrintInfo(string msg, bool iserror = false)
        {
            if (iserror == true)
            {
                this.lbInfo.ForeColor = Color.Red;
                this.lbInfo.Text = msg;
            }
            else
            {
                this.lbInfo.ForeColor = Color.Green;
                this.lbInfo.Text = msg;
            }
        }


        private void lbFileList_MouseMove(object sender, MouseEventArgs e)
        {
            ErrorCatch(() =>
            {
                showFileToolTip();
            });
        }

        private void lbFileList_MouseHover(object sender, EventArgs e)
        {
            ErrorCatch(() =>
            {
                showFileToolTip();
            });
        }

        private void FrCodeEdit_Load(object sender, EventArgs e)
        {
            ErrorCatch(() =>
            {
                TryToLoadMainFile();
            });

        }

        private void lbFileList_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ErrorCatch(() =>
            {
                if (this.lbFileList.SelectedItem != null)
                {
                    var fileinfoitem = (this.lbFileList.SelectedItem as FileInfoItem);
                    OpenFileCode(fileinfoitem);
                }
            });
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            ErrorCatch(() =>
            {
                SaveFileCode();
            });
        }

        private bool TryToLoadAssembly(string filepath)
        {
            Assembly assembly = null;
            try
            {
                assembly = Assembly.Load(filepath);
            }
            catch { }
            if (assembly != null)
                return true;
            else
                return false;
        }


        private void btnCompiler_Click(object sender, EventArgs e)
        {
            try
            {
                SaveFileCode();
                RunCompiler(EnumCompilerMode.Assembly);
                PrintInfo("编译成功:" + DateTime.Now.ToString("yyyyMMdd HH:mm:ss"));
            }
            catch (Exception exp)
            {
                PrintInfo("编译失败:" + DateTime.Now.ToString("yyyyMMdd HH:mm:ss"), true);
                if (exp is NScript.Compiler.NScriptException)
                    MessageBox.Show("编译出错:" + (exp as NScriptException).MessageDetail);
                else
                    MessageBox.Show("编译出错:" + exp.Message);
            }
        }

        private void btnDebug_Click(object sender, EventArgs e)
        {
            ErrorCatch(() =>
            {
                //frdebug.MainFileInfoItem = GetMainFileInfoItem();
                frdebug.FrParent = this;
                frdebug.Show();
            });
        }



        private void btnTemplate1_Click(object sender, EventArgs e)
        {
            new FrInfo(StringResources.CodeTemplate1).ShowDialog();
        }

        private void btnAuthor_Click(object sender, EventArgs e)
        {
            MessageBox.Show(StringResources.AuthorInfo);
        }

        private void btnAssemblyDll_Click(object sender, EventArgs e)
        {
            ErrorCatch(() =>
          {
              SaveFileCode();
              string systemdir = System.IO.Path.GetDirectoryName(typeof(string).Assembly.Location).TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
              string info = "【检查系统引用的情况，仅供参考，以实际运行为准】\n";
              #region check引用
              if (Config.SystemReferencedAssembliesDlls.Count > 0)
              {
                  info += "\n*******系统编译默认添加的程序集*******" + "\n";
                  info += "系统目录路径:" + systemdir + "\n";
                  foreach (var dll in Config.SystemReferencedAssembliesDlls)
                  {
                      if (System.IO.File.Exists(systemdir + dll))
                      {
                          info += dll + " [find file]\n";
                      }
                      else
                      {
                          info += dll + " 【文件未找到】\n";
                      }

                  }
              }
              CompilerInfo ci = new CompilerInfo().Parse(EnumSourceType.File, GetMainFileInfoItem().FullFileName);
              if (ci.DllFiles.Count > 0)
              {
                  info += "\n*******dllfiles添加dll需要引用的程序集*******" + "\n";
                  foreach (var dll in ci.DllFiles)
                  {
                      Assembly assembly = null;
                      try
                      {
                          string fullpath = dll.FullFileName;
                          if (!System.IO.File.Exists(fullpath))
                              fullpath = systemdir + dll.FileName;
                          assembly = Assembly.LoadFile(fullpath);
                      }
                      catch (Exception exp)
                      { }
                      if (assembly != null)
                      { info += dll.FileName + "[load file]\n"; }
                      else
                      { info += dll.FileName + "[加载文件失败]\n"; }
                      if (assembly != null)
                      {
                          string assemblydir = System.IO.Path.GetDirectoryName(assembly.Location);
                          foreach (var tdll in assembly.GetReferencedAssemblies())
                          {
                              var find = (from o in ci.DllFiles where o.FileName == tdll.Name + ".dll" select o).FirstOrDefault();
                              if (System.IO.File.Exists(systemdir + tdll.Name + ".dll") || System.IO.File.Exists(assemblydir + tdll.Name + ".dll")
                                  || find != null)
                              {
                                  if (Config.SystemReferencedAssembliesDlls.Contains(tdll.Name + ".dll") ||
                                      (from o in ci.DllFiles where o.FileName == tdll.Name + ".dll" select o).FirstOrDefault() != null)
                                  {
                                      info += "--" + tdll.Name + " [find file]\n";

                                  }
                                  else
                                  {
                                      info += "--" + tdll.Name + " [find file]【主文件中dllfiles未引用" + tdll.Name + ".dll文件】\n";
                                  }
                              }
                              else
                              {
                                  info += "--" + tdll.Name + " 【文件未找到】\n";
                              }
                          }
                      }

                  }
            
              }
              #endregion
              info += "\n\n" + StringResources.ReferencedAssembliesDllsHelp + "\n\n";
              new FrInfo(info, false).ShowDialog();
          });
        }

        private void btnExeHelp_Click(object sender, EventArgs e)
        {
            new FrInfo(StringResources.ExeHelp, false).ShowDialog();
        }



    }
}
